

using System;
using System.Text;
using System.IO;
using System.Security;

namespace CUtil
{
	/// <summary>
	/// Summary description for FileCopy.
	/// </summary>
	public class FileCopy
	{

		/// <summary>
		/// Error stuff
		/// </summary>
		private bool bError;
		private StringBuilder strError;

		private int nModifier = 1;
		private const int nSize = 1024;


		/// <summary>
		///  files
		/// </summary>
		private FileStream streamFromFile;
		private FileStream streamToFile;


		public bool Error
		{
			get
			{
				return bError;
			}
		}

		public string ErrorMessage
		{
			get
			{
				return strError.ToString();
			}
		}

		public int Modifier
		{
			get
			{
				return nModifier;
			}
			set
			{
				nModifier = value;
			}
		}

		/// <summary>
		/// constructor
		/// </summary>
		public FileCopy()
		{
			//
			// TODO: Add constructor logic here
			//

			bError = false;
			strError = new StringBuilder();
			strError.Remove( 0, strError.Length );
		}


		/// <summary>
		/// Open the file if a string option is passed in
		/// </summary>
		/// <param name="strFile">name of the file to open</param>
		/// <param name="bFromFile">the source or destination file</param>
		/// <returns>true on success</returns>
		private bool OpenFile( string strFile, bool bFromFile )
		{
			bError = false;
			strError.Remove( 0, strError.Length );

			try
			{
				if( bFromFile == true )
				{
					streamFromFile = new FileStream( strFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite );
				}
				else
				{
					streamToFile = new FileStream( strFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite );
				}
			}
			catch( ArgumentNullException argNullExp )
			{
				bError = true;
				strError.Append( "Error opening file " + strFile + " reason " + argNullExp.Message );
			}
			catch( PathTooLongException pathTLExp )
			{
				bError = true;
				strError.Append( "Error opening file " + strFile + " reason " + pathTLExp.Message );
			}
			catch( ArgumentOutOfRangeException argOORExp )
			{
				bError = true;
				strError.Append( "Error opening file " + strFile + " reason " + argOORExp.Message );
			}
			catch( ArgumentException argExp )
			{
				bError = true;
				strError.Append( "Error opening file " + strFile + " reason " + argExp.Message );
			}
			catch( FileNotFoundException fileNFExp )
			{
				bError = true;
				strError.Append( "Error opening file " + strFile + " reason " + fileNFExp.Message );
			}
			catch( DirectoryNotFoundException dirNFExp )
			{
				bError = true;
				strError.Append( "Error opening file " + strFile + " reason " + dirNFExp.Message );
			}
			catch( IOException ioExp )
			{
				bError = true;
				strError.Append( "Error opening file " + strFile + " reason " + ioExp.Message );
			}
			catch( SecurityException secExp )
			{
				bError = true;
				strError.Append( "Error opening file " + strFile + " reason " + secExp.Message );
			}
			catch( UnauthorizedAccessException unaExp )
			{
				bError = true;
				strError.Append( "Error opening file " + strFile + " reason " + unaExp.Message );
			}

			return bError == true? false: true;

		}

		/// <summary>
		/// the function that copies one file stream to another
		/// </summary>
		/// <returns>true on success</returns>
		private bool Copy()
		{
			bError = false;
			strError.Remove( 0, strError.Length );

			try
			{
				int nLength = 0;
				Byte[] array = new Byte[ ( nSize * nModifier ) ];
				if( ( nLength = streamFromFile.Read( array, 0, ( nSize * nModifier ) ) ) != 0 )
				{
					do
					{
						streamToFile.Write( array, 0, nLength );
					}
					while( ( nLength = streamFromFile.Read( array, 0, ( nSize * nModifier ) ) ) != 0 );
				}
													
				streamToFile.Write( array, 0, nLength );
			}
			catch( ArgumentNullException argNullExp )
			{
				strError.Append( "Error opening the file " + streamFromFile.Name + " reason " + argNullExp.Message );
				bError = true;
			}
			catch( ArgumentException argExp )
			{
				bError = true;
				strError.Append( "Error opening the file " + streamFromFile.Name + " reason " + argExp.Message );
			}
			catch( IOException ioExp )
			{
				strError.Append( "Error reading/writing to the file " + streamFromFile.Name + " reason " + ioExp.Message );
				bError = true;
			}
			catch( NotSupportedException notSException )
			{
				strError.Append( "Error reading/writing to the file " + streamFromFile.Name + " reason " + notSException.Message );
				bError = true;
			}
			catch( ObjectDisposedException objectDExp )
			{
				strError.Append( "Error reading/writing to the file " + streamFromFile.Name + " reason " + objectDExp.Message );
				bError = true;
			}

			return bError == true? false: true;
		}


		/// <summary>
		/// A stream writer version of the copy function ( isnt writing small text files correctly )
		/// </summary>
		/// <returns>true on success</returns>
		private bool CopyStream()
		{
			bError = false;
			strError.Remove( 0, strError.Length );

			try
			{
				StreamReader streamReaderTemp = new StreamReader( streamFromFile );
				StreamWriter streamWriter = new StreamWriter( streamToFile );
				StreamReader streamReader = new StreamReader( streamFromFile, streamReaderTemp.CurrentEncoding );
				streamReader.BaseStream.Seek( 0, SeekOrigin.Begin );
				streamWriter.AutoFlush = true;
				streamWriter.Write( streamReader.ReadToEnd() );
	
			}
				/// unlisted exception see description
			catch( ArgumentException argExp )
			{
				strError.Append( "Error an argument exception was thrown due to the different encodings between the reading and writing streams " + argExp.Message );
				bError = true;
			}
			catch( ObjectDisposedException odExp )
			{
				strError.Append( "Error the file trying to be written has been disposed " + streamFromFile.Name + " reason " + odExp.Message );
				bError = true;
			}
			catch( NotSupportedException nsExp )
			{
				strError.Append( "Error the stream writer is at the end of the stream " + streamFromFile.Name + " reason " + nsExp.Message );
				bError = true;
			}
			catch( OutOfMemoryException ooMemExp )
			{
				strError.Append( "Error not enough memory to read the stream " + streamFromFile.Name + " reason " + ooMemExp.Message );
				bError = true;
			}
			catch( IOException ioExp )
			{
				strError.Append( "Error io Exception reading the stream " + streamFromFile.Name + " reason " + ioExp.Message );
				bError = true;
			}
/*				/// stream writer write is throwing an exception that it doesn't list so try to catch it
			catch( Exception exp )
			{
				strError.Append( "Error unlisted exception thrown by stream writer, pitiful problem is " + exp.Message );
				bError = true;
			}
*/

			return bError == true? false: true;
		}


		/// <summary>
		/// Copy file taking two strings
		/// </summary>
		/// <param name="strFromFile">the file to be copied</param>
		/// <param name="strToFile">the file to be created</param>
		/// <returns>true on success</returns>
		public bool CopyFile( string strFromFile, string strToFile )
		{
			if( OpenFile( strFromFile, true ) == false )
			{
				bError = true;
				return false;
			}

			if( OpenFile( strToFile, false ) == false )
			{
				bError = true;
				return false;
			}

			if( Copy() == true )
			{
				this.streamFromFile.Close();
				this.streamToFile.Close();
				bError = false;
				return true;
			}
			else
			{
				bError = true;
				return false;
			}
		}

		/// <summary>
		/// Copy checked file taking two strings
		/// </summary>
		/// <param name="strFromFile">the file to be copied</param>
		/// <param name="strToFile">the file to be created</param>
		/// <returns>true on success</returns>
		public bool CopyCheckedFile( string strFromFile, string strToFile )
		{
			FileDetails fromDetails = new FileDetails( strFromFile );
			FileDetails toDetails = new FileDetails( strToFile );

			bool bCopy = false;

			if( toDetails.GetInfo.Exists == false )
				bCopy = true;

			if( fromDetails.GetInfo.LastWriteTime > toDetails.GetInfo.LastWriteTime )
				bCopy = true;

			if( bCopy == true )
			{
				streamFromFile = fromDetails.GetStream;
				streamToFile = toDetails.GetStream;

				if( Copy() == true )
				{
					this.streamFromFile.Close();
					this.streamToFile.Close();
					fromDetails.Dispose();
					toDetails.Dispose();
					bError = false;
					return true;
				}
				else
				{
					bError = true;
					return false;
				}
			}
			

			/// TODO close the file details
		
			return false;
		}

		/// <summary>
		/// copy file taking a file stream from file and a string to file
		/// </summary>
		/// <param name="streamFromFile"> File stream of the file to be copied</param>
		/// <param name="strToFile">string of the file to be created</param>
		/// <returns>true on success</returns>
		public bool CopyFile( FileStream streamFromFile, string strToFile )
		{
			this.streamFromFile = streamFromFile;

			if( OpenFile( strToFile, false ) == false )
			{
				bError = true;
				return false;
			}

			if( Copy() == true )
			{
				this.streamFromFile.Close();
				this.streamToFile.Close();
				bError = false;
				return true;
			}
			else
			{
				streamFromFile.Close();
				bError = true;
				return false;
			}
		}



		/// <summary>
		/// copy file taking a string from file and a file stream to file
		/// </summary>
		/// <param name="strFromFile">string of the file to be copied</param>
		/// <param name="streamToFile">file stream of the new file</param>
		/// <returns>true on success</returns>
		public bool CopyFile( string strFromFile, FileStream streamToFile )
		{
			this.streamToFile = streamToFile;

			if( OpenFile( strFromFile, true ) == false )
			{
				bError = true;
				return false;
			}

			if( Copy() == true )
			{
				this.streamFromFile.Close();
				this.streamToFile.Close();
				bError = false;
				return true;
			}
			else
			{
				streamToFile.Close();
				bError = true;
				return false;
			}

		}

		/// <summary>
		/// copy file taking two file streams
		/// </summary>
		/// <param name="streamFromFile">file stream for the from file</param>
		/// <param name="streamToFile">file stream for the new file</param>
		/// <returns>true on success</returns>
		public bool CopyFile( FileStream streamFromFile, FileStream streamToFile )
		{
			this.streamFromFile = streamFromFile;
			this.streamToFile = streamToFile;

			if( Copy() == true )
			{
				this.streamFromFile.Close();
				this.streamToFile.Close();
				bError = false;
				return true;
			}
			else
			{
				bError = true;
				return false;
			}
		}


		/// <summary>
		/// copy file taking two file details objects 
		/// </summary>
		/// <param name="fileDetailsFromFile">file details for the from file</param>
		/// <param name="fileDetailsToFile">file details for the to file</param>
		/// <returns>true on success</returns>
		public bool CopyFile( FileDetails fileDetailsFromFile, FileDetails fileDetailsToFile )
		{
			this.streamFromFile = fileDetailsFromFile.GetStream;
			this.streamToFile = fileDetailsToFile.GetStream;

			if( Copy() == true )
			{
				streamFromFile.Close();
				streamToFile.Close();
				bError = false;
				return true;
			}
			else
			{
				bError = true;
				return false;
			}
		}


		/// <summary>
		/// copy a file only if the file to be copied has been written to later than the file to be over written
		/// </summary>
		/// <param name="fileDetailsFromFile">the file details for the from file</param>
		/// <param name="fileDetailsToFile">the file details for the to file</param>
		/// <returns>true on success</returns>
		public bool CopyCheckedFile( FileDetails fileDetailsFromFile, FileDetails fileDetailsToFile )
		{
			bool bCopy = false;

			this.streamFromFile = fileDetailsFromFile.GetStream;
			FileInfo fileInfo = fileDetailsFromFile.GetInfo;

			this.streamToFile = fileDetailsToFile.GetStream;
			FileInfo localInfo = fileDetailsToFile.GetInfo;

			if( localInfo.Exists == false )
				bCopy = true;
			else
			{
				if( fileInfo.LastWriteTime > localInfo.LastWriteTime )
					bCopy = true;
				else
				{
					streamFromFile.Close();
					streamToFile.Close();
				}
			}

			if( bCopy == true )
			{

				if( Copy() == true )
				{
					bError = false;
					return true;
				}
				else
				{
					streamFromFile.Close();
					streamToFile.Close();
					bError = true;
					return false;
				}
			}

			return false;
		}
	}
}



